#!/usr/bin/env python
'''
PyCoi - Controller program for the RaspberryCoi system.
Copyright (C) 2013  B. Wilbertz

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
'''

import logging
from PyCoiGlobals import logFile
FORMAT="%(asctime)s: %(levelname)s - %(message)s"
logging.basicConfig(level=logging.INFO,filename=logFile,format=FORMAT,datefmt='%Y-%m-%d %H:%M:%S')
 
import sys,time
import RPi.GPIO as GPIO
from PyQt4 import QtCore, QtGui, QtDeclarative

from Display import DisplayUpdater, DisplayConnection
from OperatingState import OperatingState
from CoiThreads import PumpThread,BlinkThread,ControlThread,GPIOThread,TemperatureAndLogThread
from PyCoiGlobals import statFile,pins
from Utilities import xstr

def main():
    try:
        # initializing environment
        #logging.basicConfig(level=logging.INFO)
        #logging.root.setLevel(logging.INFO)
        logging.debug('Starting PyCoi...')
        
        overrideGPIOWiring()
        
        state = OperatingState()
        setupGPIO()
        readAndSetLastOilDistance(state)
        
        # ini GUI
        displayUpdater = DisplayUpdater()
        
        app = QtGui.QApplication(sys.argv)
        
        # Create the QML user interface.
        view = QtDeclarative.QDeclarativeView()
        view.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        view.setSource(QtCore.QUrl('GUI.qml'))
        view.setCursor(QtGui.QCursor(QtCore.Qt.BlankCursor))
        
        rootObject = view.rootObject()
        
        connection = DisplayConnection()
        connection.connectToSlot(rootObject)
        
        state.displayConnection = connection
                
        view.show()
            
        # creating and launching threads
        pumpThread = PumpThread(state)
        pumpThread.start()
        
        blinkThread = BlinkThread(state)
        blinkThread.start()
        
        gpioThread = GPIOThread(state)
        gpioThread.start()
        
        temperatureAndLogThread = TemperatureAndLogThread(state)
        temperatureAndLogThread.start()
        
        controlThread = ControlThread(state, displayUpdater, app)
        controlThread.start()
        
        #testThread = TestThread(state)
        #testThread.start()
              
        try:
            app.exec_()
        finally:
            # waiting for the end TODO clean up GPIO thread / GPIO
            logging.warning("GUI has quit. Initiating shutdown...")
            state.nPumpStrokes = 0
            state.OK = False
            state.pumpEvent.set()
            GPIO.cleanup()
            
    except Exception,e:
        logging.fatal("Exception during initialization: " + str(e))    
      
def readAndSetLastOilDistance(state):
    if statFile is not None:
        try:
            with open(statFile, 'r') as f:
                x = float(f.readline())
                z = int(f.readline())
                y = int(f.readline())
                
                if hash(str(x+z)) == y:
                    state.oilDistance = x
                    state.rainMode = bool(z)
                    state.xtraModePumpStrokes = z
                    logging.info("Successfully read previous state from file: " + xstr(state))
                else:
                    state.oilDistance = 0.0
                    logging.warn("Checksum error in saved state from file. Discarding dist value " + xstr(x) + ". Distance is initialized to 0.")
                    
        except Exception,e:
            state.oilDistance = 0.0
            logging.warn("Unexpected error while reading previous state from file " + xstr(statFile) + ". Setting distance to 0. Exception: " + xstr(e))
            
    
def getSerialNumber():
    fileName = "/proc/cpuinfo"

    serial = "0000000000000000"
    
    try:
        with open(fileName, 'r') as f:
            for line in f:
                if line[0:6]=='Serial':
                    serial = line[10:26]
    except:
        logging.warn("Unable to retrieve serial number")
        serial = "ERROR000000000"            
        
        
    return serial

def overrideGPIOWiring():
    if getSerialNumber() == "000000001a53b349":
        pins.rainModeLED = 10
        pins.crossModeSwitch = 9
        logging.info("Overriding GPIO Pins: rainLED = " + str(pins.rainModeLED) 
                     + "; crossModeSwitch = " + str(pins.crossModeSwitch) )
    
def setupGPIO():
    GPIO.setwarnings(True)
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(pins.pump, GPIO.OUT)
    GPIO.setup(pins.crossModeLED, GPIO.OUT)
    GPIO.setup(pins.rainModeLED, GPIO.OUT)
    GPIO.setup(pins.crossModeSwitch, GPIO.IN, GPIO.PUD_UP)
    GPIO.setup(pins.rainSensor, GPIO.IN, GPIO.PUD_UP)
    GPIO.setup(pins.rainSensorOut1, GPIO.OUT)
    GPIO.setup(pins.rainSensorOut2, GPIO.OUT)
    
def doTestStuff(state):
    time.sleep(10)
    state.crossMode = True
    state.crossModeEvent.set()
    
    time.sleep(10)
    state.crossMode = False
    state.crossModeEvent.set()
    
    time.sleep(10)
    state.pumpEvent.set()
    
    time.sleep(10)
    state.pumpEvent.set()
    
    
if __name__ == '__main__':
    main()
